import { computed, h, defineComponent, resolveComponent, ref } from 'vue';
import { useClickOutside, useNamespace } from '@ibiz-template/vue3-util';
import { OnClickOutsideResult } from '@ibiz-template/core';
import { GridFieldEditColumnController } from './grid-field-edit-column.controller';
import { GridRowState } from '../../grid/grid-row.state';

export const GridFieldEditColumn = defineComponent({
  name: 'GridFieldEditColumn',
  props: {
    controller: {
      type: GridFieldEditColumnController,
      required: true,
    },
    row: {
      type: GridRowState,
      required: true,
    },
  },
  setup(props) {
    const ns = useNamespace('grid-field-edit-column');

    const c = props.controller;
    const fieldName = c.editItem.codeName!;

    // 编辑器值变更事件
    const rowDataChange = async (
      val: unknown,
      name?: string,
    ): Promise<void> => {
      ibiz.log.debug(`${fieldName}值变更`, val);
      await c.setRowValue(props.row, val, name);
    };

    // 是否是单元格编辑
    const isCellEdit = ibiz.config.grid.editShowMode === 'cell';
    // 单元格行编辑下，单个出禁用无意义，所以禁用走的还是只读
    const isDisabled = computed(() => {
      return props.row.editColStates[fieldName.toLowerCase()].disabled;
    });
    // 单元格行编辑下，需要自动聚焦，每次变更编辑态的时候就需要聚焦到对应的编辑器内部。
    const isAutoFocus = computed(() => isCellEdit);

    /** 控制行编辑编辑态切换的状态变量 */
    const editable = computed(
      () => props.row.editColStates[fieldName.toLowerCase()].editable,
    );
    const setEditable = (flag: boolean): void => {
      // eslint-disable-next-line vue/no-mutating-props, no-param-reassign
      props.row.editColStates[fieldName.toLowerCase()].editable = flag;
    };

    const editorReadOnly = computed(() => {
      // 编辑器配了只读，或者所有行编辑时，禁用也呈现为只读
      const readOnly = c.readOnly || isDisabled.value;
      // 非只读的时候，编辑关闭且没有报错的时候才显示只读
      return readOnly || (!editable.value && !props.row.errors[fieldName]);
    });
    const editorDisabled = computed(() => {
      return false;
    });

    const showEditMask = computed(() => {
      return (
        isCellEdit &&
        !isDisabled.value &&
        !c.readOnly &&
        !props.row.errors[fieldName] &&
        !editable.value
      );
    });

    /** 是否阻止内部点击冒泡 */
    const stopPropagation = computed(() => {
      return showEditMask.value && !editorReadOnly.value;
    });

    // 点击遮罩后，开启编辑，然后监听外部点击，外部点击之后关闭编辑
    let funs: OnClickOutsideResult;
    const componentRef = ref();
    const onMaskClick = (): void => {
      setEditable(true);
      funs = useClickOutside(componentRef, async _evt => {
        setEditable(false);
        funs.stop();
      });
    };

    // 聚焦事件，关闭外部点击监听，由编辑器的blur关闭编辑
    const onFocus = (): void => {
      if (funs) {
        funs.stop();
      }
      ibiz.log.debug(`${fieldName}属性编辑器focus事件`);
    };
    const onBlur = (): void => {
      ibiz.log.debug(`${fieldName}属性编辑器blur事件`);
      // 单元格编辑的时候恢复信息态
      if (isCellEdit) {
        setEditable(false);
      }
      // 失焦保存模式时，触发保存
      if (ibiz.config.grid.editSaveMode === 'cell-blur') {
        c.grid.save(props.row.data);
      }
    };

    return {
      ns,
      c,
      fieldName,
      editorReadOnly,
      editorDisabled,
      isAutoFocus,
      showEditMask,
      stopPropagation,
      componentRef,
      rowDataChange,
      onMaskClick,
      onBlur,
      onFocus,
    };
  },
  render() {
    return (
      <iBizGridEditItem
        ref='componentRef'
        required={!this.c.editItem.allowEmpty}
        error={this.row.errors[this.fieldName]}
        showEditMask={this.showEditMask}
        stopPropagation={this.stopPropagation}
        onMaskClick={this.onMaskClick}
      >
        {this.c.editorProvider &&
          h(resolveComponent(this.c.editorProvider.gridEditor), {
            value: this.row.data[this.fieldName],
            data: this.row.data,
            controller: this.c.editor,
            disabled: this.editorDisabled,
            autoFocus: this.isAutoFocus,
            readonly: this.editorReadOnly,
            onChange: this.rowDataChange,
            onFocus: this.onFocus,
            onBlur: this.onBlur,
          })}
      </iBizGridEditItem>
    );
  },
});
export default GridFieldEditColumn;
